home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / guile / 1.8 / oop / goops.scm
Encoding:
Text File  |  2008-12-17  |  51.5 KB  |  1,716 lines

  1. ;;; installed-scm-file
  2.  
  3. ;;;; Copyright (C) 1998,1999,2000,2001,2002, 2003, 2006 Free Software Foundation, Inc.
  4. ;;;; 
  5. ;;;; This library is free software; you can redistribute it and/or
  6. ;;;; modify it under the terms of the GNU Lesser General Public
  7. ;;;; License as published by the Free Software Foundation; either
  8. ;;;; version 2.1 of the License, or (at your option) any later version.
  9. ;;;; 
  10. ;;;; This library is distributed in the hope that it will be useful,
  11. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. ;;;; Lesser General Public License for more details.
  14. ;;;; 
  15. ;;;; You should have received a copy of the GNU Lesser General Public
  16. ;;;; License along with this library; if not, write to the Free Software
  17. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. ;;;; 
  19.  
  20.  
  21. ;;;; This software is a derivative work of other copyrighted softwares; the
  22. ;;;; copyright notices of these softwares are placed in the file COPYRIGHTS
  23. ;;;;
  24. ;;;; This file is based upon stklos.stk from the STk distribution by
  25. ;;;; Erick Gallesio <eg@unice.fr>.
  26. ;;;;
  27.  
  28. (define-module (oop goops)
  29.   :export-syntax (define-class class standard-define-class
  30.           define-generic define-accessor define-method
  31.           define-extended-generic define-extended-generics
  32.           method)
  33.   :export (goops-version is-a? class-of
  34.            ensure-metaclass ensure-metaclass-with-supers
  35.        make-class
  36.        make-generic ensure-generic
  37.        make-extended-generic
  38.        make-accessor ensure-accessor
  39.        process-class-pre-define-generic
  40.        process-class-pre-define-accessor
  41.        process-define-generic
  42.        process-define-accessor
  43.        make-method add-method!
  44.        object-eqv? object-equal?
  45.        class-slot-ref class-slot-set! slot-unbound slot-missing 
  46.        slot-definition-name  slot-definition-options
  47.        slot-definition-allocation
  48.        slot-definition-getter slot-definition-setter
  49.        slot-definition-accessor
  50.        slot-definition-init-value slot-definition-init-form
  51.        slot-definition-init-thunk slot-definition-init-keyword 
  52.        slot-init-function class-slot-definition
  53.        method-source
  54.        compute-cpl compute-std-cpl compute-get-n-set compute-slots
  55.        compute-getter-method compute-setter-method
  56.        allocate-instance initialize make-instance make
  57.        no-next-method  no-applicable-method no-method
  58.        change-class update-instance-for-different-class
  59.        shallow-clone deep-clone
  60.        class-redefinition
  61.        apply-generic apply-method apply-methods
  62.        compute-applicable-methods %compute-applicable-methods
  63.        method-more-specific? sort-applicable-methods
  64.        class-subclasses class-methods
  65.        goops-error
  66.        min-fixnum max-fixnum
  67.        ;;; *fixme* Should go into goops.c
  68.        instance?  slot-ref-using-class
  69.        slot-set-using-class! slot-bound-using-class?
  70.        slot-exists-using-class? slot-ref slot-set! slot-bound?
  71.        class-name class-direct-supers class-direct-subclasses
  72.        class-direct-methods class-direct-slots class-precedence-list
  73.        class-slots class-environment
  74.        generic-function-name
  75.        generic-function-methods method-generic-function method-specializers
  76.        primitive-generic-generic enable-primitive-generic!
  77.        method-procedure accessor-method-slot-definition
  78.        slot-exists? make find-method get-keyword)
  79.   :replace (<class> <operator-class> <entity-class> <entity>)
  80.   :no-backtrace)
  81.  
  82. ;; First initialize the builtin part of GOOPS
  83. (%init-goops-builtins)
  84.  
  85. ;; Then load the rest of GOOPS
  86. (use-modules (oop goops util)
  87.          (oop goops dispatch)
  88.          (oop goops compile))
  89.  
  90.  
  91. (define min-fixnum (- (expt 2 29)))
  92.  
  93. (define max-fixnum (- (expt 2 29) 1))
  94.  
  95. ;;
  96. ;; goops-error
  97. ;;
  98. (define (goops-error format-string . args)
  99.   (save-stack)
  100.   (scm-error 'goops-error #f format-string args '()))
  101.  
  102. ;;
  103. ;; is-a?
  104. ;;
  105. (define (is-a? obj class)
  106.   (and (memq class (class-precedence-list (class-of obj))) #t))
  107.  
  108.  
  109. ;;;
  110. ;;; {Meta classes}
  111. ;;;
  112.  
  113. (define ensure-metaclass-with-supers
  114.   (let ((table-of-metas '()))
  115.     (lambda (meta-supers)
  116.       (let ((entry (assoc meta-supers table-of-metas)))
  117.     (if entry
  118.         ;; Found a previously created metaclass
  119.         (cdr entry)
  120.         ;; Create a new meta-class which inherit from "meta-supers"
  121.         (let ((new (make <class> #:dsupers meta-supers
  122.                          #:slots   '()
  123.                      #:name   (gensym "metaclass"))))
  124.           (set! table-of-metas (cons (cons meta-supers new) table-of-metas))
  125.           new))))))
  126.  
  127. (define (ensure-metaclass supers env)
  128.   (if (null? supers)
  129.       <class>
  130.       (let* ((all-metas (map (lambda (x) (class-of x)) supers))
  131.          (all-cpls  (apply append
  132.                    (map (lambda (m)
  133.                       (cdr (class-precedence-list m))) 
  134.                     all-metas)))
  135.          (needed-metas '()))
  136.     ;; Find the most specific metaclasses.  The new metaclass will be
  137.     ;; a subclass of these.
  138.     (for-each
  139.      (lambda (meta)
  140.        (if (and (not (member meta all-cpls))
  141.               (not (member meta needed-metas)))
  142.          (set! needed-metas (append needed-metas (list meta)))))
  143.      all-metas)
  144.     ;; Now return a subclass of the metaclasses we found.
  145.     (if (null? (cdr needed-metas))
  146.         (car needed-metas)  ; If there's only one, just use it.
  147.         (ensure-metaclass-with-supers needed-metas)))))
  148.  
  149. ;;;
  150. ;;; {Classes}
  151. ;;;
  152.  
  153. ;;; (define-class NAME (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  154. ;;;
  155. ;;;   SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  156. ;;;   OPTION ::= KEYWORD VALUE
  157. ;;;
  158. (define (define-class-pre-definition keyword exp env)
  159.   (case keyword
  160.     ((#:getter #:setter)
  161.      `(process-class-pre-define-generic ',exp))
  162.     ((#:accessor)
  163.      `(process-class-pre-define-accessor ',exp))
  164.     (else #f)))
  165.  
  166. (define (process-class-pre-define-generic name)
  167.   (let ((var (module-variable (current-module) name)))
  168.     (if (not (and var
  169.           (variable-bound? var)
  170.           (is-a? (variable-ref var) <generic>)))
  171.     (process-define-generic name))))
  172.  
  173. (define (process-class-pre-define-accessor name)
  174.   (let ((var (module-variable (current-module) name)))
  175.     (cond ((or (not var)
  176.            (not (variable-bound? var)))
  177.        (process-define-accessor name))
  178.       ((or (is-a? (variable-ref var) <accessor>)
  179.            (is-a? (variable-ref var) <extended-generic-with-setter>)))
  180.       ((is-a? (variable-ref var) <generic>)
  181.        ;;*fixme* don't mutate an imported object!
  182.        (variable-set! var (ensure-accessor (variable-ref var) name)))
  183.       (else
  184.        (process-define-accessor name)))))
  185.  
  186. ;;; This code should be implemented in C.
  187. ;;;
  188. (define define-class
  189.   (letrec (;; Some slot options require extra definitions to be made.
  190.        ;; In particular, we want to make sure that the generic
  191.        ;; function objects which represent accessors exist
  192.        ;; before `make-class' tries to add methods to them.
  193.        ;;
  194.        ;; Postpone error handling to class macro.
  195.        ;;
  196.        (pre-definitions
  197.         (lambda (slots env)
  198.           (do ((slots slots (cdr slots))
  199.            (definitions '()
  200.              (if (pair? (car slots))
  201.              (do ((options (cdar slots) (cddr options))
  202.                   (definitions definitions
  203.                 (cond ((not (symbol? (cadr options)))
  204.                        definitions)
  205.                       ((define-class-pre-definition
  206.                      (car options)
  207.                      (cadr options)
  208.                      env)
  209.                        => (lambda (definition)
  210.                         (cons definition definitions)))
  211.                       (else definitions))))
  212.                  ((not (and (pair? options)
  213.                     (pair? (cdr options))))
  214.                   definitions))
  215.              definitions)))
  216.           ((or (not (pair? slots))
  217.                (keyword? (car slots)))
  218.            (reverse definitions)))))
  219.        
  220.        ;; Syntax
  221.        (name cadr)
  222.        (slots cdddr))
  223.     
  224.     (procedure->memoizing-macro
  225.       (lambda (exp env)
  226.     (cond ((not (top-level-env? env))
  227.            (goops-error "define-class: Only allowed at top level"))
  228.           ((not (and (list? exp) (>= (length exp) 3)))
  229.            (goops-error "missing or extra expression"))
  230.           (else
  231.            (let ((name (name exp)))
  232.          `(begin
  233.             ;; define accessors
  234.             ,@(pre-definitions (slots exp) env)
  235.             ;; update the current-module
  236.             (let* ((class (class ,@(cddr exp) #:name ',name))
  237.                (var (module-ensure-local-variable!
  238.                  (current-module) ',name))
  239.                (old (and (variable-bound? var)
  240.                      (variable-ref var))))
  241.               (if (and old
  242.                    (is-a? old <class>)
  243.                    (memq <object> (class-precedence-list old)))
  244.               (variable-set! var (class-redefinition old class))
  245.               (variable-set! var class)))))))))))
  246.  
  247. (define standard-define-class define-class)
  248.  
  249. ;;; (class (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  250. ;;;
  251. ;;;   SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  252. ;;;   OPTION ::= KEYWORD VALUE
  253. ;;;
  254. (define class
  255.   (letrec ((slot-option-keyword car)
  256.        (slot-option-value cadr)
  257.        (process-slot-options
  258.         (lambda (options)
  259.           (let loop ((options options)
  260.              (res '()))
  261.         (cond ((null? options)
  262.                (reverse res))
  263.               ((null? (cdr options))
  264.                (goops-error "malformed slot option list"))
  265.               ((not (keyword? (slot-option-keyword options)))
  266.                (goops-error "malformed slot option list"))
  267.               (else
  268.                (case (slot-option-keyword options)
  269.              ((#:init-form)
  270.               (loop (cddr options)
  271.                 (append (list `(lambda ()
  272.                          ,(slot-option-value options))
  273.                           #:init-thunk
  274.                           (list 'quote
  275.                             (slot-option-value options))
  276.                           #:init-form)
  277.                     res)))
  278.              (else
  279.               (loop (cddr options)
  280.                 (cons (cadr options)
  281.                       (cons (car options)
  282.                         res)))))))))))
  283.     
  284.     (procedure->memoizing-macro
  285.       (let ((supers cadr)
  286.         (slots cddr)
  287.         (options cdddr))
  288.     (lambda (exp env)
  289.       (cond ((not (and (list? exp) (>= (length exp) 2)))
  290.          (goops-error "missing or extra expression"))
  291.         ((not (list? (supers exp)))
  292.          (goops-error "malformed superclass list: ~S" (supers exp)))
  293.         (else
  294.          (let ((slot-defs (cons #f '())))
  295.            (do ((slots (slots exp) (cdr slots))
  296.             (defs slot-defs (cdr defs)))
  297.                ((or (null? slots)
  298.                 (keyword? (car slots)))
  299.             `(make-class
  300.               ;; evaluate super class variables
  301.               (list ,@(supers exp))
  302.               ;; evaluate slot definitions, except the slot name!
  303.               (list ,@(cdr slot-defs))
  304.               ;; evaluate class options
  305.               ,@slots
  306.               ;; place option last in case someone wants to
  307.               ;; pass a different value
  308.               #:environment ',env))
  309.              (set-cdr!
  310.               defs
  311.               (list (if (pair? (car slots))
  312.                 `(list ',(slot-definition-name (car slots))
  313.                        ,@(process-slot-options
  314.                       (slot-definition-options
  315.                        (car slots))))
  316.                 `(list ',(car slots))))))))))))))
  317.  
  318. (define (make-class supers slots . options)
  319.   (let ((env (or (get-keyword #:environment options #f)
  320.          (top-level-env))))
  321.     (let* ((name (get-keyword #:name options (make-unbound)))
  322.        (supers (if (not (or-map (lambda (class)
  323.                       (memq <object>
  324.                         (class-precedence-list class)))
  325.                     supers))
  326.                (append supers (list <object>))
  327.                supers))
  328.        (metaclass (or (get-keyword #:metaclass options #f)
  329.               (ensure-metaclass supers env))))
  330.  
  331.       ;; Verify that all direct slots are different and that we don't inherit
  332.       ;; several time from the same class
  333.       (let ((tmp1 (find-duplicate supers))
  334.         (tmp2 (find-duplicate (map slot-definition-name slots))))
  335.     (if tmp1
  336.         (goops-error "make-class: super class ~S is duplicate in class ~S"
  337.              tmp1 name))
  338.     (if tmp2
  339.         (goops-error "make-class: slot ~S is duplicate in class ~S"
  340.              tmp2 name)))
  341.  
  342.       ;; Everything seems correct, build the class
  343.       (apply make metaclass
  344.          #:dsupers supers
  345.          #:slots slots 
  346.          #:name name
  347.          #:environment env
  348.          options))))
  349.  
  350. ;;;
  351. ;;; {Generic functions and accessors}
  352. ;;;
  353.  
  354. (define define-generic
  355.   (procedure->memoizing-macro
  356.     (lambda (exp env)
  357.       (let ((name (cadr exp)))
  358.     (cond ((not (symbol? name))
  359.            (goops-error "bad generic function name: ~S" name))
  360.           ((top-level-env? env)
  361.            `(process-define-generic ',name))
  362.           (else
  363.            `(define ,name (make <generic> #:name ',name))))))))
  364.  
  365. (define (process-define-generic name)
  366.   (let ((var (module-ensure-local-variable! (current-module) name)))
  367.     (if (or (not var)
  368.         (not (variable-bound? var))
  369.         (is-a? (variable-ref var) <generic>))
  370.     ;; redefine if NAME isn't defined previously, or is another generic
  371.     (variable-set! var (make <generic> #:name name))
  372.     ;; otherwise try to upgrade the object to a generic
  373.     (variable-set! var (ensure-generic (variable-ref var) name)))))
  374.  
  375. (define define-extended-generic
  376.   (procedure->memoizing-macro
  377.     (lambda (exp env)
  378.       (let ((name (cadr exp)))
  379.     (cond ((not (symbol? name))
  380.            (goops-error "bad generic function name: ~S" name))
  381.           ((null? (cddr exp))
  382.            (goops-error "missing expression"))
  383.           (else
  384.            `(define ,name (make-extended-generic ,(caddr exp) ',name))))))))
  385. (define define-extended-generics
  386.   (procedure->memoizing-macro
  387.     (lambda (exp env)
  388.       (let ((names (cadr exp))
  389.         (prefixes (get-keyword #:prefix (cddr exp) #f)))
  390.     (if prefixes
  391.         `(begin
  392.            ,@(map (lambda (name)
  393.             `(define-extended-generic ,name
  394.                (list ,@(map (lambda (prefix)
  395.                       (symbol-append prefix name))
  396.                     prefixes))))
  397.               names))
  398.         (goops-error "no prefixes supplied"))))))
  399.  
  400. (define (make-generic . name)
  401.   (let ((name (and (pair? name) (car name))))
  402.     (make <generic> #:name name)))
  403.  
  404. (define (make-extended-generic gfs . name)
  405.   (let* ((name (and (pair? name) (car name)))
  406.      (gfs (if (pair? gfs) gfs (list gfs)))
  407.      (gws? (any (lambda (gf) (is-a? gf <generic-with-setter>)) gfs)))
  408.     (let ((ans (if gws?
  409.            (let* ((sname (and name (make-setter-name name)))
  410.               (setters
  411.                (apply append
  412.                   (map (lambda (gf)
  413.                      (if (is-a? gf <generic-with-setter>)
  414.                          (list (ensure-generic (setter gf)
  415.                                    sname))
  416.                          '()))
  417.                        gfs)))
  418.               (es (make <extended-generic-with-setter>
  419.                 #:name name
  420.                 #:extends gfs
  421.                 #:setter (make <extended-generic>
  422.                        #:name sname
  423.                        #:extends setters))))
  424.              (extended-by! setters (setter es))
  425.              es)
  426.            (make <extended-generic>
  427.              #:name name
  428.              #:extends gfs))))
  429.       (extended-by! gfs ans)
  430.       ans)))
  431.  
  432. (define (extended-by! gfs eg)
  433.   (for-each (lambda (gf)
  434.           (slot-set! gf 'extended-by
  435.              (cons eg (slot-ref gf 'extended-by))))
  436.         gfs))
  437.  
  438. (define (not-extended-by! gfs eg)
  439.   (for-each (lambda (gf)
  440.           (slot-set! gf 'extended-by
  441.              (delq! eg (slot-ref gf 'extended-by))))
  442.         gfs))
  443.  
  444. (define (ensure-generic old-definition . name)
  445.   (let ((name (and (pair? name) (car name))))
  446.     (cond ((is-a? old-definition <generic>) old-definition)
  447.       ((procedure-with-setter? old-definition)
  448.        (make <generic-with-setter>
  449.          #:name name
  450.          #:default (procedure old-definition)
  451.          #:setter (setter old-definition)))
  452.       ((procedure? old-definition)
  453.        (make <generic> #:name name #:default old-definition))
  454.       (else (make <generic> #:name name)))))
  455.  
  456. (define define-accessor
  457.   (procedure->memoizing-macro
  458.     (lambda (exp env)
  459.       (let ((name (cadr exp)))
  460.     (cond ((not (symbol? name))
  461.            (goops-error "bad accessor name: ~S" name))
  462.           ((top-level-env? env)
  463.            `(process-define-accessor ',name))
  464.           (else
  465.            `(define ,name (make-accessor ',name))))))))
  466.  
  467. (define (process-define-accessor name)
  468.   (let ((var (module-ensure-local-variable! (current-module) name)))
  469.     (if (or (not var)
  470.         (not (variable-bound? var))
  471.         (is-a? (variable-ref var) <accessor>)
  472.         (is-a? (variable-ref var) <extended-generic-with-setter>))
  473.     ;; redefine if NAME isn't defined previously, or is another accessor
  474.     (variable-set! var (make-accessor name))
  475.     ;; otherwise try to upgrade the object to an accessor
  476.     (variable-set! var (ensure-accessor (variable-ref var) name)))))
  477.  
  478. (define (make-setter-name name)
  479.   (string->symbol (string-append "setter:" (symbol->string name))))
  480.  
  481. (define (make-accessor . name)
  482.   (let ((name (and (pair? name) (car name))))
  483.     (make <accessor>
  484.       #:name name
  485.       #:setter (make <generic>
  486.                  #:name (and name (make-setter-name name))))))
  487.  
  488. (define (ensure-accessor proc . name)
  489.   (let ((name (and (pair? name) (car name))))
  490.     (cond ((and (is-a? proc <accessor>)
  491.         (is-a? (setter proc) <generic>))
  492.        proc)
  493.       ((is-a? proc <generic-with-setter>)
  494.        (upgrade-accessor proc (setter proc)))
  495.       ((is-a? proc <generic>)
  496.        (upgrade-accessor proc (make-generic name)))
  497.       ((procedure-with-setter? proc)
  498.        (make <accessor>
  499.          #:name name
  500.          #:default (procedure proc)
  501.          #:setter (ensure-generic (setter proc) name)))
  502.       ((procedure? proc)
  503.        (ensure-accessor (ensure-generic proc name) name))
  504.       (else
  505.        (make-accessor name)))))
  506.  
  507. (define (upgrade-accessor generic setter)
  508.   (let ((methods (slot-ref generic 'methods))
  509.     (gws (make (if (is-a? generic <extended-generic>)
  510.                <extended-generic-with-setter>
  511.                <accessor>)
  512.            #:name (generic-function-name generic)
  513.            #:extended-by (slot-ref generic 'extended-by)
  514.            #:setter setter)))
  515.     (if (is-a? generic <extended-generic>)
  516.     (let ((gfs (slot-ref generic 'extends)))
  517.       (not-extended-by! gfs generic)
  518.       (slot-set! gws 'extends gfs)
  519.       (extended-by! gfs gws)))
  520.     ;; Steal old methods
  521.     (for-each (lambda (method)
  522.         (slot-set! method 'generic-function gws))
  523.           methods)
  524.     (slot-set! gws 'methods methods)
  525.     gws))
  526.  
  527. ;;;
  528. ;;; {Methods}
  529. ;;;
  530.  
  531. (define define-method
  532.   (procedure->memoizing-macro
  533.     (lambda (exp env)
  534.       (let ((head (cadr exp)))
  535.     (if (not (pair? head))
  536.         (goops-error "bad method head: ~S" head)
  537.         (let ((gf (car head)))
  538.           (cond ((and (pair? gf)
  539.               (eq? (car gf) 'setter)
  540.               (pair? (cdr gf))
  541.               (symbol? (cadr gf))
  542.               (null? (cddr gf)))
  543.              ;; named setter method
  544.              (let ((name (cadr gf)))
  545.                (cond ((not (symbol? name))
  546.                   `(add-method! (setter ,name)
  547.                         (method ,(cdadr exp)
  548.                             ,@(cddr exp))))
  549.                  ((defined? name env)
  550.                   `(begin
  551.                  ;; *fixme* Temporary hack for the current
  552.                  ;;         module system
  553.                  (if (not ,name)
  554.                      (define-accessor ,name))
  555.                  (add-method! (setter ,name)
  556.                           (method ,(cdadr exp)
  557.                               ,@(cddr exp)))))
  558.                  (else
  559.                   `(begin
  560.                  (define-accessor ,name)
  561.                  (add-method! (setter ,name)
  562.                           (method ,(cdadr exp)
  563.                               ,@(cddr exp))))))))
  564.             ((not (symbol? gf))
  565.              `(add-method! ,gf (method ,(cdadr exp) ,@(cddr exp))))
  566.             ((defined? gf env)
  567.              `(begin
  568.             ;; *fixme* Temporary hack for the current
  569.             ;;         module system
  570.             (if (not ,gf)
  571.                 (define-generic ,gf))
  572.             (add-method! ,gf
  573.                      (method ,(cdadr exp)
  574.                          ,@(cddr exp)))))
  575.             (else
  576.              `(begin
  577.             (define-generic ,gf)
  578.             (add-method! ,gf
  579.                      (method ,(cdadr exp)
  580.                          ,@(cddr exp))))))))))))
  581.  
  582. (define (make-method specializers procedure)
  583.   (make <method>
  584.     #:specializers specializers
  585.     #:procedure procedure))
  586.  
  587. (define method
  588.   (letrec ((specializers
  589.         (lambda (ls)
  590.           (cond ((null? ls) (list (list 'quote '())))
  591.             ((pair? ls) (cons (if (pair? (car ls))
  592.                       (cadar ls)
  593.                       '<top>)
  594.                       (specializers (cdr ls))))
  595.             (else '(<top>)))))
  596.        (formals
  597.         (lambda (ls)
  598.           (if (pair? ls)
  599.           (cons (if (pair? (car ls)) (caar ls) (car ls))
  600.             (formals (cdr ls)))
  601.           ls))))
  602.     (procedure->memoizing-macro
  603.       (lambda (exp env)
  604.     (let ((args (cadr exp))
  605.           (body (cddr exp)))
  606.       `(make <method>
  607.          #:specializers (cons* ,@(specializers args))
  608.          #:procedure (lambda ,(formals args)
  609.                    ,@(if (null? body)
  610.                      (list *unspecified*)
  611.                      body))))))))
  612.  
  613. ;;;
  614. ;;; {add-method!}
  615. ;;;
  616.  
  617. (define (add-method-in-classes! m)
  618.   ;; Add method in all the classes which appears in its specializers list
  619.   (for-each* (lambda (x)
  620.            (let ((dm (class-direct-methods x)))
  621.          (if (not (memv m dm))
  622.              (slot-set! x 'direct-methods (cons m dm)))))
  623.          (method-specializers m)))
  624.  
  625. (define (remove-method-in-classes! m)
  626.   ;; Remove method in all the classes which appears in its specializers list
  627.   (for-each* (lambda (x)
  628.            (slot-set! x
  629.               'direct-methods
  630.               (delv! m (class-direct-methods x))))
  631.          (method-specializers m)))
  632.  
  633. (define (compute-new-list-of-methods gf new)
  634.   (let ((new-spec (method-specializers new))
  635.     (methods  (slot-ref gf 'methods)))
  636.     (let loop ((l methods))
  637.       (if (null? l)
  638.       (cons new methods)
  639.       (if (equal? (method-specializers (car l)) new-spec)
  640.           (begin 
  641.         ;; This spec. list already exists. Remove old method from dependents
  642.         (remove-method-in-classes! (car l))
  643.         (set-car! l new) 
  644.         methods)
  645.           (loop (cdr l)))))))
  646.  
  647. (define (internal-add-method! gf m)
  648.   (slot-set! m  'generic-function gf)
  649.   (slot-set! gf 'methods (compute-new-list-of-methods gf m))
  650.   (let ((specializers (slot-ref m 'specializers)))
  651.     (slot-set! gf 'n-specialized
  652.            (max (length* specializers)
  653.             (slot-ref gf 'n-specialized))))
  654.   (%invalidate-method-cache! gf)
  655.   (add-method-in-classes! m)
  656.   *unspecified*)
  657.  
  658. (define-generic add-method!)
  659.  
  660. (internal-add-method! add-method!
  661.               (make <method>
  662.             #:specializers (list <generic> <method>)
  663.             #:procedure internal-add-method!))
  664.  
  665. (define-method (add-method! (proc <procedure>) (m <method>))
  666.   (if (generic-capability? proc)
  667.       (begin
  668.     (enable-primitive-generic! proc)
  669.     (add-method! proc m))
  670.       (next-method)))
  671.  
  672. (define-method (add-method! (pg <primitive-generic>) (m <method>))
  673.   (add-method! (primitive-generic-generic pg) m))
  674.  
  675. (define-method (add-method! obj (m <method>))
  676.   (goops-error "~S is not a valid generic function" obj))
  677.  
  678. ;;;
  679. ;;; {Access to meta objects}
  680. ;;;
  681.  
  682. ;;;
  683. ;;; Methods
  684. ;;;
  685. (define-method (method-source (m <method>))
  686.   (let* ((spec (map* class-name (slot-ref m 'specializers)))
  687.      (proc (procedure-source (slot-ref m 'procedure)))
  688.      (args (cadr proc))
  689.      (body (cddr proc)))
  690.     (cons 'method
  691.       (cons (map* list args spec)
  692.         body))))
  693.  
  694. ;;;
  695. ;;; Slots
  696. ;;;
  697. (define slot-definition-name car)
  698.  
  699. (define slot-definition-options cdr)
  700.  
  701. (define (slot-definition-allocation s)
  702.   (get-keyword #:allocation (cdr s) #:instance))
  703.  
  704. (define (slot-definition-getter s)
  705.   (get-keyword #:getter (cdr s) #f))
  706.  
  707. (define (slot-definition-setter s)
  708.   (get-keyword #:setter (cdr s) #f))
  709.  
  710. (define (slot-definition-accessor s)
  711.   (get-keyword #:accessor (cdr s) #f))
  712.  
  713. (define (slot-definition-init-value s)
  714.   ;; can be #f, so we can't use #f as non-value
  715.   (get-keyword #:init-value (cdr s) (make-unbound)))
  716.  
  717. (define (slot-definition-init-form s)
  718.   (get-keyword #:init-form (cdr s) (make-unbound)))
  719.  
  720. (define (slot-definition-init-thunk s)
  721.   (get-keyword #:init-thunk (cdr s) #f))
  722.  
  723. (define (slot-definition-init-keyword s)
  724.   (get-keyword #:init-keyword (cdr s) #f))
  725.  
  726. (define (class-slot-definition class slot-name)
  727.   (assq slot-name (class-slots class)))
  728.  
  729. (define (slot-init-function class slot-name)
  730.   (cadr (assq slot-name (slot-ref class 'getters-n-setters))))
  731.  
  732.  
  733. ;;;
  734. ;;; {Standard methods used by the C runtime}
  735. ;;;
  736.  
  737. ;;; Methods to compare objects
  738. ;;;
  739.  
  740. (define-method (eqv? x y) #f)
  741. (define-method (equal? x y) (eqv? x y))
  742.  
  743. ;;; These following two methods are for backward compatibility only.
  744. ;;; They are not called by the Guile interpreter.
  745. ;;;
  746. (define-method (object-eqv? x y)    #f)
  747. (define-method (object-equal? x y)  (eqv? x y))
  748.  
  749. ;;;
  750. ;;; methods to display/write an object
  751. ;;;
  752.  
  753. ;     Code for writing objects must test that the slots they use are
  754. ;     bound. Otherwise a slot-unbound method will be called and will 
  755. ;     conduct to an infinite loop.
  756.  
  757. ;; Write
  758. (define (display-address o file)
  759.   (display (number->string (object-address o) 16) file))
  760.  
  761. (define-method (write o file)
  762.   (display "#<instance " file)
  763.   (display-address o file)
  764.   (display #\> file))
  765.  
  766. (define write-object (primitive-generic-generic write))
  767.  
  768. (define-method (write (o <object>) file)
  769.   (let ((class (class-of o)))
  770.     (if (slot-bound? class 'name)
  771.     (begin
  772.       (display "#<" file)
  773.       (display (class-name class) file)
  774.       (display #\space file)
  775.       (display-address o file)
  776.       (display #\> file))
  777.     (next-method))))
  778.  
  779. (define-method (write (o <foreign-object>) file)
  780.   (let ((class (class-of o)))
  781.     (if (slot-bound? class 'name)
  782.     (begin
  783.       (display "#<foreign-object " file)
  784.       (display (class-name class) file)
  785.       (display #\space file)
  786.       (display-address o file)
  787.       (display #\> file))
  788.     (next-method))))
  789.  
  790. (define-method (write (class <class>) file)
  791.   (let ((meta (class-of class)))
  792.     (if (and (slot-bound? class 'name)
  793.          (slot-bound? meta 'name))
  794.     (begin
  795.       (display "#<" file)
  796.       (display (class-name meta) file)
  797.       (display #\space file)
  798.       (display (class-name class) file)
  799.       (display #\space file)
  800.       (display-address class file)
  801.       (display #\> file))
  802.     (next-method))))
  803.  
  804. (define-method (write (gf <generic>) file)
  805.   (let ((meta (class-of gf)))
  806.     (if (and (slot-bound? meta 'name)
  807.          (slot-bound? gf 'methods))
  808.     (begin
  809.       (display "#<" file)
  810.       (display (class-name meta) file)
  811.       (let ((name (generic-function-name gf)))
  812.         (if name
  813.         (begin
  814.           (display #\space file)
  815.           (display name file))))
  816.       (display " (" file)
  817.       (display (length (generic-function-methods gf)) file)
  818.       (display ")>" file))
  819.     (next-method))))
  820.  
  821. (define-method (write (o <method>) file)
  822.   (let ((meta (class-of o)))
  823.     (if (and (slot-bound? meta 'name)
  824.          (slot-bound? o 'specializers))
  825.     (begin
  826.       (display "#<" file)
  827.       (display (class-name meta) file)
  828.       (display #\space file)
  829.       (display (map* (lambda (spec)
  830.                (if (slot-bound? spec 'name)
  831.                    (slot-ref spec 'name)
  832.                    spec))
  833.              (method-specializers o))
  834.            file)
  835.       (display #\space file)
  836.       (display-address o file)
  837.       (display #\> file))
  838.     (next-method))))
  839.  
  840. ;; Display (do the same thing as write by default)
  841. (define-method (display o file) 
  842.   (write-object o file))
  843.  
  844. ;;;
  845. ;;; Handling of duplicate bindings in the module system
  846. ;;;
  847.  
  848. (define-method (merge-generics (module <module>)
  849.                    (name <symbol>)
  850.                    (int1 <module>)
  851.                    (val1 <top>)
  852.                    (int2 <module>)
  853.                    (val2 <top>)
  854.                    (var <top>)
  855.                    (val <top>))
  856.   #f)
  857.  
  858. (define-method (merge-generics (module <module>)
  859.                    (name <symbol>)
  860.                    (int1 <module>)
  861.                    (val1 <generic>)
  862.                    (int2 <module>)
  863.                    (val2 <generic>)
  864.                    (var <top>)
  865.                    (val <boolean>))
  866.   (and (not (eq? val1 val2))
  867.        (make-variable (make-extended-generic (list val2 val1) name))))
  868.  
  869. (define-method (merge-generics (module <module>)
  870.                    (name <symbol>)
  871.                    (int1 <module>)
  872.                    (val1 <generic>)
  873.                    (int2 <module>)
  874.                    (val2 <generic>)
  875.                    (var <top>)
  876.                    (gf <extended-generic>))
  877.   (and (not (memq val2 (slot-ref gf 'extends)))
  878.        (begin
  879.      (slot-set! gf
  880.             'extends
  881.             (cons val2 (delq! val2 (slot-ref gf 'extends))))
  882.      (slot-set! val2
  883.             'extended-by
  884.             (cons gf (delq! gf (slot-ref val2 'extended-by))))
  885.      var)))
  886.  
  887. (module-define! duplicate-handlers 'merge-generics merge-generics)
  888.  
  889. (define-method (merge-accessors (module <module>)
  890.                 (name <symbol>)
  891.                 (int1 <module>)
  892.                 (val1 <top>)
  893.                 (int2 <module>)
  894.                 (val2 <top>)
  895.                 (var <top>)
  896.                 (val <top>))
  897.   #f)
  898.  
  899. (define-method (merge-accessors (module <module>)
  900.                 (name <symbol>)
  901.                 (int1 <module>)
  902.                 (val1 <accessor>)
  903.                 (int2 <module>)
  904.                 (val2 <accessor>)
  905.                 (var <top>)
  906.                 (val <top>))
  907.   (merge-generics module name int1 val1 int2 val2 var val))
  908.  
  909. (module-define! duplicate-handlers 'merge-accessors merge-accessors)
  910.  
  911. ;;;
  912. ;;; slot access
  913. ;;;
  914.  
  915. (define (class-slot-g-n-s class slot-name)
  916.   (let* ((this-slot (assq slot-name (slot-ref class 'slots)))
  917.      (g-n-s (cddr (or (assq slot-name (slot-ref class 'getters-n-setters))
  918.               (slot-missing class slot-name)))))
  919.     (if (not (memq (slot-definition-allocation this-slot)
  920.            '(#:class #:each-subclass)))
  921.     (slot-missing class slot-name))
  922.     g-n-s))
  923.  
  924. (define (class-slot-ref class slot)
  925.   (let ((x ((car (class-slot-g-n-s class slot)) #f)))
  926.     (if (unbound? x)
  927.     (slot-unbound class slot)
  928.     x)))
  929.  
  930. (define (class-slot-set! class slot value)
  931.   ((cadr (class-slot-g-n-s class slot)) #f value))
  932.  
  933. (define-method (slot-unbound (c <class>) (o <object>) s)
  934.   (goops-error "Slot `~S' is unbound in object ~S" s o))
  935.  
  936. (define-method (slot-unbound (c <class>) s)
  937.   (goops-error "Slot `~S' is unbound in class ~S" s c))
  938.  
  939. (define-method (slot-unbound (o <object>))
  940.   (goops-error "Unbound slot in object ~S" o))
  941.  
  942. (define-method (slot-missing (c <class>) (o <object>) s)
  943.   (goops-error "No slot with name `~S' in object ~S" s o))
  944.   
  945. (define-method (slot-missing (c <class>) s)
  946.   (goops-error "No class slot with name `~S' in class ~S" s c))
  947.   
  948.  
  949. (define-method (slot-missing (c <class>) (o <object>) s value)
  950.   (slot-missing c o s))
  951.  
  952. ;;; Methods for the possible error we can encounter when calling a gf
  953.  
  954. (define-method (no-next-method (gf <generic>) args)
  955.   (goops-error "No next method when calling ~S\nwith arguments ~S" gf args))
  956.  
  957. (define-method (no-applicable-method (gf <generic>) args)
  958.   (goops-error "No applicable method for ~S in call ~S"
  959.            gf (cons (generic-function-name gf) args)))
  960.  
  961. (define-method (no-method (gf <generic>) args)
  962.   (goops-error "No method defined for ~S"  gf))
  963.  
  964. ;;;
  965. ;;; {Cloning functions (from rdeline@CS.CMU.EDU)}
  966. ;;;
  967.  
  968. (define-method (shallow-clone (self <object>))
  969.   (let ((clone (%allocate-instance (class-of self) '()))
  970.     (slots (map slot-definition-name
  971.             (class-slots (class-of self)))))
  972.     (for-each (lambda (slot)
  973.         (if (slot-bound? self slot)
  974.             (slot-set! clone slot (slot-ref self slot))))
  975.           slots)
  976.     clone))
  977.  
  978. (define-method (deep-clone  (self <object>))
  979.   (let ((clone (%allocate-instance (class-of self) '()))
  980.     (slots (map slot-definition-name
  981.             (class-slots (class-of self)))))
  982.     (for-each (lambda (slot)
  983.         (if (slot-bound? self slot)
  984.             (slot-set! clone slot
  985.                    (let ((value (slot-ref self slot)))
  986.                  (if (instance? value)
  987.                      (deep-clone value)
  988.                      value)))))
  989.           slots)
  990.     clone))
  991.  
  992. ;;;
  993. ;;; {Class redefinition utilities}
  994. ;;;
  995.  
  996. ;;; (class-redefinition OLD NEW)
  997. ;;;
  998.  
  999. ;;; Has correct the following conditions:
  1000.  
  1001. ;;; Methods
  1002. ;;; 
  1003. ;;; 1. New accessor specializers refer to new header
  1004. ;;; 
  1005. ;;; Classes
  1006. ;;; 
  1007. ;;; 1. New class cpl refers to the new class header
  1008. ;;; 2. Old class header exists on old super classes direct-subclass lists
  1009. ;;; 3. New class header exists on new super classes direct-subclass lists
  1010.  
  1011. (define-method (class-redefinition (old <class>) (new <class>))
  1012.   ;; Work on direct methods:
  1013.   ;;        1. Remove accessor methods from the old class 
  1014.   ;;        2. Patch the occurences of new in the specializers by old
  1015.   ;;        3. Displace the methods from old to new
  1016.   (remove-class-accessors! old)                    ;; -1-
  1017.   (let ((methods (class-direct-methods new)))
  1018.     (for-each (lambda (m)
  1019.                   (update-direct-method! m new old))    ;; -2-
  1020.               methods)
  1021.     (slot-set! new
  1022.            'direct-methods
  1023.            (append methods (class-direct-methods old))))
  1024.  
  1025.   ;; Substitute old for new in new cpl
  1026.   (set-car! (slot-ref new 'cpl) old)
  1027.   
  1028.   ;; Remove the old class from the direct-subclasses list of its super classes
  1029.   (for-each (lambda (c) (slot-set! c 'direct-subclasses
  1030.                    (delv! old (class-direct-subclasses c))))
  1031.         (class-direct-supers old))
  1032.  
  1033.   ;; Replace the new class with the old in the direct-subclasses of the supers
  1034.   (for-each (lambda (c)
  1035.           (slot-set! c 'direct-subclasses
  1036.              (cons old (delv! new (class-direct-subclasses c)))))
  1037.         (class-direct-supers new))
  1038.  
  1039.   ;; Swap object headers
  1040.   (%modify-class old new)
  1041.  
  1042.   ;; Now old is NEW!
  1043.  
  1044.   ;; Redefine all the subclasses of old to take into account modification
  1045.   (for-each 
  1046.        (lambda (c)
  1047.      (update-direct-subclass! c new old))
  1048.        (class-direct-subclasses new))
  1049.  
  1050.   ;; Invalidate class so that subsequent instances slot accesses invoke
  1051.   ;; change-object-class
  1052.   (slot-set! new 'redefined old)
  1053.   (%invalidate-class new) ;must come after slot-set!
  1054.  
  1055.   old)
  1056.  
  1057. ;;;
  1058. ;;; remove-class-accessors!
  1059. ;;;
  1060.  
  1061. (define-method (remove-class-accessors! (c <class>))
  1062.   (for-each (lambda (m)
  1063.           (if (is-a? m <accessor-method>)
  1064.           (let ((gf (slot-ref m 'generic-function)))
  1065.             ;; remove the method from its GF
  1066.             (slot-set! gf 'methods
  1067.                    (delq1! m (slot-ref gf 'methods)))
  1068.             (%invalidate-method-cache! gf)
  1069.             ;; remove the method from its specializers
  1070.             (remove-method-in-classes! m))))
  1071.         (class-direct-methods c)))
  1072.  
  1073. ;;;
  1074. ;;; update-direct-method!
  1075. ;;;
  1076.  
  1077. (define-method (update-direct-method! (m  <method>)
  1078.                       (old <class>)
  1079.                       (new <class>))
  1080.   (let loop ((l (method-specializers m)))
  1081.     ;; Note: the <top> in dotted list is never used. 
  1082.     ;; So we can work as if we had only proper lists.
  1083.     (if (pair? l)             
  1084.     (begin
  1085.       (if (eqv? (car l) old)  
  1086.           (set-car! l new))
  1087.       (loop (cdr l))))))
  1088.  
  1089. ;;;
  1090. ;;; update-direct-subclass!
  1091. ;;;
  1092.  
  1093. (define-method (update-direct-subclass! (c <class>)
  1094.                     (old <class>)
  1095.                     (new <class>))
  1096.   (class-redefinition c
  1097.               (make-class (class-direct-supers c)
  1098.                   (class-direct-slots c)
  1099.                   #:name (class-name c)
  1100.                   #:environment (slot-ref c 'environment)
  1101.                   #:metaclass (class-of c))))
  1102.  
  1103. ;;;
  1104. ;;; {Utilities for INITIALIZE methods}
  1105. ;;;
  1106.  
  1107. ;;; compute-slot-accessors
  1108. ;;;
  1109. (define (compute-slot-accessors class slots env)
  1110.   (for-each
  1111.       (lambda (s g-n-s)
  1112.     (let ((name            (slot-definition-name     s))
  1113.           (getter-function (slot-definition-getter   s))
  1114.           (setter-function (slot-definition-setter   s))
  1115.           (accessor        (slot-definition-accessor s)))
  1116.       (if getter-function
  1117.           (add-method! getter-function
  1118.                (compute-getter-method class g-n-s)))
  1119.       (if setter-function
  1120.           (add-method! setter-function
  1121.                (compute-setter-method class g-n-s)))
  1122.       (if accessor
  1123.           (begin
  1124.         (add-method! accessor
  1125.                  (compute-getter-method class g-n-s))
  1126.         (add-method! (setter accessor)
  1127.                  (compute-setter-method class g-n-s))))))
  1128.       slots (slot-ref class 'getters-n-setters)))
  1129.  
  1130. (define-method (compute-getter-method (class <class>) slotdef)
  1131.   (let ((init-thunk (cadr slotdef))
  1132.     (g-n-s (cddr slotdef)))
  1133.     (make <accessor-method>
  1134.           #:specializers (list class)
  1135.       #:procedure (cond ((pair? g-n-s)
  1136.                  (make-generic-bound-check-getter (car g-n-s)))
  1137.                 (init-thunk
  1138.                  (standard-get g-n-s))
  1139.                 (else
  1140.                  (bound-check-get g-n-s)))
  1141.       #:slot-definition slotdef)))
  1142.  
  1143. (define-method (compute-setter-method (class <class>) slotdef)
  1144.   (let ((g-n-s (cddr slotdef)))
  1145.     (make <accessor-method>
  1146.           #:specializers (list class <top>)
  1147.       #:procedure (if (pair? g-n-s)
  1148.               (cadr g-n-s)
  1149.               (standard-set g-n-s))
  1150.       #:slot-definition slotdef)))
  1151.  
  1152. (define (make-generic-bound-check-getter proc)
  1153.   (let ((source (and (closure? proc) (procedure-source proc))))
  1154.     (if (and source (null? (cdddr source)))
  1155.     (let ((obj (caadr source)))
  1156.       ;; smart closure compilation
  1157.       (local-eval
  1158.        `(lambda (,obj) (,assert-bound ,(caddr source) ,obj))
  1159.        (procedure-environment proc)))
  1160.     (lambda (o) (assert-bound (proc o) o)))))
  1161.  
  1162. (define n-standard-accessor-methods 10)
  1163.  
  1164. (define bound-check-get-methods (make-vector n-standard-accessor-methods #f))
  1165. (define standard-get-methods (make-vector n-standard-accessor-methods #f))
  1166. (define standard-set-methods (make-vector n-standard-accessor-methods #f))
  1167.  
  1168. (define (standard-accessor-method make methods)
  1169.   (lambda (index)
  1170.     (cond ((>= index n-standard-accessor-methods) (make index))
  1171.       ((vector-ref methods index))
  1172.       (else (let ((m (make index)))
  1173.           (vector-set! methods index m)
  1174.           m)))))
  1175.  
  1176. (define (make-bound-check-get index)
  1177.   (local-eval `(lambda (o) (@assert-bound-ref o ,index)) (the-environment)))
  1178.  
  1179. (define (make-get index)
  1180.   (local-eval `(lambda (o) (@slot-ref o ,index)) (the-environment)))
  1181.  
  1182. (define (make-set index)
  1183.   (local-eval `(lambda (o v) (@slot-set! o ,index v)) (the-environment)))
  1184.  
  1185. (define bound-check-get
  1186.   (standard-accessor-method make-bound-check-get bound-check-get-methods))
  1187. (define standard-get (standard-accessor-method make-get standard-get-methods))
  1188. (define standard-set (standard-accessor-method make-set standard-set-methods))
  1189.  
  1190. ;;; compute-getters-n-setters
  1191. ;;;
  1192. (define (make-thunk thunk)
  1193.   (lambda () (thunk)))
  1194.  
  1195. (define (compute-getters-n-setters class slots env)
  1196.  
  1197.   (define (compute-slot-init-function name s)
  1198.     (or (let ((thunk (slot-definition-init-thunk s)))
  1199.       (and thunk
  1200.            (cond ((not (thunk? thunk))
  1201.               (goops-error "Bad init-thunk for slot `~S' in ~S: ~S"
  1202.                    name class thunk))
  1203.              ((closure? thunk) thunk)
  1204.              (else (make-thunk thunk)))))
  1205.     (let ((init (slot-definition-init-value s)))
  1206.       (and (not (unbound? init))
  1207.            (lambda () init)))))
  1208.  
  1209.   (define (verify-accessors slot l)
  1210.     (cond ((integer? l))
  1211.       ((not (and (list? l) (= (length l) 2)))
  1212.        (goops-error "Bad getter and setter for slot `~S' in ~S: ~S"
  1213.             slot class l))
  1214.       (else
  1215.        (let ((get (car l)) 
  1216.          (set (cadr l)))
  1217.          (if (not (and (closure? get)
  1218.                (= (car (procedure-property get 'arity)) 1)))
  1219.          (goops-error "Bad getter closure for slot `~S' in ~S: ~S"
  1220.                   slot class get))
  1221.          (if (not (and (closure? set)
  1222.                (= (car (procedure-property set 'arity)) 2)))
  1223.          (goops-error "Bad setter closure for slot `~S' in ~S: ~S"
  1224.                   slot class set))))))
  1225.  
  1226.   (map (lambda (s)
  1227.      ;; The strange treatment of nfields is due to backward compatibility.
  1228.      (let* ((index (slot-ref class 'nfields))
  1229.         (g-n-s (compute-get-n-set class s))
  1230.         (size (- (slot-ref class 'nfields) index))
  1231.         (name  (slot-definition-name s)))
  1232.        ;; NOTE: The following is interdependent with C macros
  1233.        ;; defined above goops.c:scm_sys_prep_layout_x.
  1234.        ;;
  1235.        ;; For simple instance slots, we have the simplest form
  1236.        ;; '(name init-function . index)
  1237.        ;; For other slots we have
  1238.        ;; '(name init-function getter setter . alloc)
  1239.        ;; where alloc is:
  1240.        ;;   '(index size) for instance allocated slots
  1241.        ;;   '() for other slots
  1242.        (verify-accessors name g-n-s)
  1243.        (cons name
  1244.          (cons (compute-slot-init-function name s)
  1245.                (if (or (integer? g-n-s)
  1246.                    (zero? size))
  1247.                g-n-s
  1248.                (append g-n-s (list index size)))))))
  1249.        slots))
  1250.  
  1251. ;;; compute-cpl
  1252. ;;;
  1253. ;;; Correct behaviour:
  1254. ;;;
  1255. ;;; (define-class food ())
  1256. ;;; (define-class fruit (food))
  1257. ;;; (define-class spice (food))
  1258. ;;; (define-class apple (fruit))
  1259. ;;; (define-class cinnamon (spice))
  1260. ;;; (define-class pie (apple cinnamon))
  1261. ;;; => cpl (pie) = pie apple fruit cinnamon spice food object top
  1262. ;;;
  1263. ;;; (define-class d ())
  1264. ;;; (define-class e ())
  1265. ;;; (define-class f ())
  1266. ;;; (define-class b (d e))
  1267. ;;; (define-class c (e f))
  1268. ;;; (define-class a (b c))
  1269. ;;; => cpl (a) = a b d c e f object top
  1270. ;;;
  1271.  
  1272. (define-method (compute-cpl (class <class>))
  1273.   (compute-std-cpl class class-direct-supers))
  1274.  
  1275. ;; Support
  1276.  
  1277. (define (only-non-null lst)
  1278.   (filter (lambda (l) (not (null? l))) lst))
  1279.  
  1280. (define (compute-std-cpl c get-direct-supers)
  1281.   (let ((c-direct-supers (get-direct-supers c)))
  1282.     (merge-lists (list c)
  1283.                  (only-non-null (append (map class-precedence-list
  1284.                          c-direct-supers)
  1285.                                         (list c-direct-supers))))))
  1286.  
  1287. (define (merge-lists reversed-partial-result inputs)
  1288.   (cond
  1289.    ((every null? inputs)
  1290.     (reverse! reversed-partial-result))
  1291.    (else
  1292.     (let* ((candidate (lambda (c)
  1293.                         (and (not (any (lambda (l)
  1294.                                          (memq c (cdr l)))
  1295.                                        inputs))
  1296.                              c)))
  1297.            (candidate-car (lambda (l)
  1298.                             (and (not (null? l))
  1299.                                  (candidate (car l)))))
  1300.            (next (any candidate-car inputs)))
  1301.       (if (not next)
  1302.           (goops-error "merge-lists: Inconsistent precedence graph"))
  1303.       (let ((remove-next (lambda (l)
  1304.                            (if (eq? (car l) next)
  1305.                                (cdr l)
  1306.                              l))))
  1307.         (merge-lists (cons next reversed-partial-result)
  1308.                      (only-non-null (map remove-next inputs))))))))
  1309.  
  1310. ;; Modified from TinyClos:
  1311. ;;
  1312. ;; A simple topological sort.
  1313. ;;
  1314. ;; It's in this file so that both TinyClos and Objects can use it.
  1315. ;;
  1316. ;; This is a fairly modified version of code I originally got from Anurag
  1317. ;; Mendhekar <anurag@moose.cs.indiana.edu>.
  1318. ;;
  1319.  
  1320. (define (compute-clos-cpl c get-direct-supers)
  1321.   (top-sort ((build-transitive-closure get-direct-supers) c)
  1322.         ((build-constraints get-direct-supers) c)
  1323.         (std-tie-breaker get-direct-supers)))
  1324.  
  1325.  
  1326. (define (top-sort elements constraints tie-breaker)
  1327.   (let loop ((elements    elements)
  1328.          (constraints constraints)
  1329.          (result      '()))
  1330.     (if (null? elements)
  1331.     result
  1332.     (let ((can-go-in-now
  1333.            (filter
  1334.         (lambda (x)
  1335.           (every (lambda (constraint)
  1336.                (or (not (eq? (cadr constraint) x))
  1337.                    (memq (car constraint) result)))
  1338.              constraints))
  1339.         elements)))
  1340.       (if (null? can-go-in-now)
  1341.           (goops-error "top-sort: Invalid constraints")
  1342.           (let ((choice (if (null? (cdr can-go-in-now))
  1343.                 (car can-go-in-now)
  1344.                 (tie-breaker result
  1345.                          can-go-in-now))))
  1346.         (loop
  1347.          (filter (lambda (x) (not (eq? x choice)))
  1348.              elements)
  1349.          constraints
  1350.          (append result (list choice)))))))))
  1351.  
  1352. (define (std-tie-breaker get-supers)
  1353.   (lambda (partial-cpl min-elts)
  1354.     (let loop ((pcpl (reverse partial-cpl)))
  1355.       (let ((current-elt (car pcpl)))
  1356.     (let ((ds-of-ce (get-supers current-elt)))
  1357.       (let ((common (filter (lambda (x)
  1358.                       (memq x ds-of-ce))
  1359.                     min-elts)))
  1360.         (if (null? common)
  1361.         (if (null? (cdr pcpl))
  1362.             (goops-error "std-tie-breaker: Nothing valid")
  1363.             (loop (cdr pcpl)))
  1364.         (car common))))))))
  1365.  
  1366.  
  1367. (define (build-transitive-closure get-follow-ons)
  1368.   (lambda (x)
  1369.     (let track ((result '())
  1370.         (pending (list x)))
  1371.       (if (null? pending)
  1372.       result
  1373.       (let ((next (car pending)))
  1374.         (if (memq next result)
  1375.         (track result (cdr pending))
  1376.         (track (cons next result)
  1377.                (append (get-follow-ons next)
  1378.                    (cdr pending)))))))))
  1379.  
  1380. (define (build-constraints get-follow-ons)
  1381.   (lambda (x)
  1382.     (let loop ((elements ((build-transitive-closure get-follow-ons) x))
  1383.            (this-one '())
  1384.            (result '()))
  1385.       (if (or (null? this-one) (null? (cdr this-one)))
  1386.       (if (null? elements)
  1387.           result
  1388.           (loop (cdr elements)
  1389.             (cons (car elements)
  1390.               (get-follow-ons (car elements)))
  1391.             result))
  1392.       (loop elements
  1393.         (cdr this-one)
  1394.         (cons (list (car this-one) (cadr this-one))
  1395.               result))))))
  1396.  
  1397. ;;; compute-get-n-set
  1398. ;;;
  1399. (define-method (compute-get-n-set (class <class>) s)
  1400.   (case (slot-definition-allocation s)
  1401.     ((#:instance) ;; Instance slot
  1402.      ;; get-n-set is just its offset
  1403.      (let ((already-allocated (slot-ref class 'nfields)))
  1404.        (slot-set! class 'nfields (+ already-allocated 1))
  1405.        already-allocated))
  1406.  
  1407.     ((#:class)  ;; Class slot
  1408.      ;; Class-slots accessors are implemented as 2 closures around 
  1409.      ;; a Scheme variable. As instance slots, class slots must be
  1410.      ;; unbound at init time.
  1411.      (let ((name (slot-definition-name s)))
  1412.        (if (memq name (map slot-definition-name (class-direct-slots class)))
  1413.        ;; This slot is direct; create a new shared variable
  1414.        (make-closure-variable class)
  1415.        ;; Slot is inherited. Find its definition in superclass
  1416.        (let loop ((l (cdr (class-precedence-list class))))
  1417.          (let ((r (assoc name (slot-ref (car l) 'getters-n-setters))))
  1418.            (if r
  1419.            (cddr r)
  1420.            (loop (cdr l))))))))
  1421.  
  1422.     ((#:each-subclass) ;; slot shared by instances of direct subclass.
  1423.      ;; (Thomas Buerger, April 1998)
  1424.      (make-closure-variable class))
  1425.  
  1426.     ((#:virtual) ;; No allocation
  1427.      ;; slot-ref and slot-set! function must be given by the user
  1428.      (let ((get (get-keyword #:slot-ref  (slot-definition-options s) #f))
  1429.        (set (get-keyword #:slot-set! (slot-definition-options s) #f))
  1430.        (env (class-environment class)))
  1431.        (if (not (and get set))
  1432.        (goops-error "You must supply a #:slot-ref and a #:slot-set! in ~S"
  1433.             s))
  1434.        (list get set)))
  1435.     (else    (next-method))))
  1436.  
  1437. (define (make-closure-variable class)
  1438.   (let ((shared-variable (make-unbound)))
  1439.     (list (lambda (o) shared-variable)
  1440.       (lambda (o v) (set! shared-variable v)))))
  1441.  
  1442. (define-method (compute-get-n-set (o <object>) s)
  1443.   (goops-error "Allocation \"~S\" is unknown" (slot-definition-allocation s)))
  1444.  
  1445. (define-method (compute-slots (class <class>))
  1446.   (%compute-slots class))
  1447.  
  1448. ;;;
  1449. ;;; {Initialize}
  1450. ;;;
  1451.  
  1452. (define-method (initialize (object <object>) initargs)
  1453.   (%initialize-object object initargs))
  1454.  
  1455. (define-method (initialize (class <class>) initargs)
  1456.   (next-method)
  1457.   (let ((dslots (get-keyword #:slots initargs '()))
  1458.     (supers (get-keyword #:dsupers      initargs '()))
  1459.     (env    (get-keyword #:environment initargs (top-level-env))))
  1460.  
  1461.     (slot-set! class 'name          (get-keyword #:name initargs '???))
  1462.     (slot-set! class 'direct-supers     supers)
  1463.     (slot-set! class 'direct-slots      dslots)
  1464.     (slot-set! class 'direct-subclasses '())
  1465.     (slot-set! class 'direct-methods    '())
  1466.     (slot-set! class 'cpl        (compute-cpl class))
  1467.     (slot-set! class 'redefined        #f)
  1468.     (slot-set! class 'environment    env)
  1469.     (let ((slots (compute-slots class)))
  1470.       (slot-set! class 'slots            slots)
  1471.       (slot-set! class 'nfields            0)
  1472.       (slot-set! class 'getters-n-setters (compute-getters-n-setters class 
  1473.                                      slots 
  1474.                                      env))
  1475.       ;; Build getters - setters - accessors
  1476.       (compute-slot-accessors class slots env))
  1477.  
  1478.     ;; Update the "direct-subclasses" of each inherited classes
  1479.     (for-each (lambda (x)
  1480.         (slot-set! x
  1481.                'direct-subclasses 
  1482.                (cons class (slot-ref x 'direct-subclasses))))
  1483.           supers)
  1484.  
  1485.     ;; Support for the underlying structs:
  1486.     
  1487.     ;; Inherit class flags (invisible on scheme level) from supers
  1488.     (%inherit-magic! class supers)
  1489.  
  1490.     ;; Set the layout slot
  1491.     (%prep-layout! class)))
  1492.  
  1493. (define (initialize-object-procedure object initargs)
  1494.   (let ((proc (get-keyword #:procedure initargs #f)))
  1495.     (cond ((not proc))
  1496.       ((pair? proc)
  1497.        (apply set-object-procedure! object proc))
  1498.       ((valid-object-procedure? proc)
  1499.        (set-object-procedure! object proc))
  1500.       (else
  1501.        (set-object-procedure! object
  1502.                   (lambda args (apply proc args)))))))
  1503.  
  1504. (define-method (initialize (class <operator-class>) initargs)
  1505.   (next-method)
  1506.   (initialize-object-procedure class initargs))
  1507.  
  1508. (define-method (initialize (owsc <operator-with-setter-class>) initargs)
  1509.   (next-method)
  1510.   (%set-object-setter! owsc (get-keyword #:setter initargs #f)))
  1511.  
  1512. (define-method (initialize (entity <entity>) initargs)
  1513.   (next-method)
  1514.   (initialize-object-procedure entity initargs))
  1515.  
  1516. (define-method (initialize (ews <entity-with-setter>) initargs)
  1517.   (next-method)
  1518.   (%set-object-setter! ews (get-keyword #:setter initargs #f)))
  1519.  
  1520. (define-method (initialize (generic <generic>) initargs)
  1521.   (let ((previous-definition (get-keyword #:default initargs #f))
  1522.     (name (get-keyword #:name initargs #f)))
  1523.     (next-method)
  1524.     (slot-set! generic 'methods (if (is-a? previous-definition <procedure>)
  1525.                     (list (make <method>
  1526.                         #:specializers <top>
  1527.                         #:procedure
  1528.                         (lambda l
  1529.                           (apply previous-definition 
  1530.                              l))))
  1531.                     '()))
  1532.     (if name
  1533.     (set-procedure-property! generic 'name name))
  1534.     ))
  1535.  
  1536. (define-method (initialize (eg <extended-generic>) initargs)
  1537.   (next-method)
  1538.   (slot-set! eg 'extends (get-keyword #:extends initargs '())))
  1539.  
  1540. (define dummy-procedure (lambda args *unspecified*))
  1541.  
  1542. (define-method (initialize (method <method>) initargs)
  1543.   (next-method)
  1544.   (slot-set! method 'generic-function (get-keyword #:generic-function initargs #f))
  1545.   (slot-set! method 'specializers (get-keyword #:specializers initargs '()))
  1546.   (slot-set! method 'procedure
  1547.          (get-keyword #:procedure initargs dummy-procedure))
  1548.   (slot-set! method 'code-table '()))
  1549.  
  1550. (define-method (initialize (obj <foreign-object>) initargs))
  1551.  
  1552. ;;;
  1553. ;;; {Change-class}
  1554. ;;;
  1555.  
  1556. (define (change-object-class old-instance old-class new-class)
  1557.   (let ((new-instance (allocate-instance new-class '())))
  1558.     ;; Initialize the slots of the new instance
  1559.     (for-each (lambda (slot)
  1560.         (if (and (slot-exists-using-class? old-class old-instance slot)
  1561.              (eq? (slot-definition-allocation
  1562.                    (class-slot-definition old-class slot))
  1563.                   #:instance)
  1564.              (slot-bound-using-class? old-class old-instance slot))
  1565.             ;; Slot was present and allocated in old instance; copy it 
  1566.             (slot-set-using-class!
  1567.              new-class 
  1568.              new-instance 
  1569.              slot 
  1570.              (slot-ref-using-class old-class old-instance slot))
  1571.             ;; slot was absent; initialize it with its default value
  1572.             (let ((init (slot-init-function new-class slot)))
  1573.               (if init
  1574.               (slot-set-using-class!
  1575.                    new-class 
  1576.                    new-instance 
  1577.                    slot
  1578.                    (apply init '()))))))
  1579.           (map slot-definition-name (class-slots new-class)))
  1580.     ;; Exchange old and new instance in place to keep pointers valid
  1581.     (%modify-instance old-instance new-instance)
  1582.     ;; Allow class specific updates of instances (which now are swapped)
  1583.     (update-instance-for-different-class new-instance old-instance)
  1584.     old-instance))
  1585.  
  1586.  
  1587. (define-method (update-instance-for-different-class (old-instance <object>)
  1588.                             (new-instance
  1589.                              <object>))
  1590.   ;;not really important what we do, we just need a default method
  1591.   new-instance)
  1592.  
  1593. (define-method (change-class (old-instance <object>) (new-class <class>))
  1594.   (change-object-class old-instance (class-of old-instance) new-class))
  1595.  
  1596. ;;;
  1597. ;;; {make}
  1598. ;;;
  1599. ;;; A new definition which overwrites the previous one which was built-in
  1600. ;;;
  1601.  
  1602. (define-method (allocate-instance (class <class>) initargs)
  1603.   (%allocate-instance class initargs))
  1604.  
  1605. (define-method (make-instance (class <class>) . initargs)
  1606.   (let ((instance (allocate-instance class initargs)))
  1607.     (initialize instance initargs)
  1608.     instance))
  1609.  
  1610. (define make make-instance)
  1611.  
  1612. ;;;
  1613. ;;; {apply-generic}
  1614. ;;;
  1615. ;;; Protocol for calling standard generic functions.  This protocol is
  1616. ;;; not used for real <generic> functions (in this case we use a
  1617. ;;; completely C hard-coded protocol).  Apply-generic is used by
  1618. ;;; goops for calls to subclasses of <generic> and <generic-with-setter>.
  1619. ;;; The code below is similar to the first MOP described in AMOP. In
  1620. ;;; particular, it doesn't used the currified approach to gf
  1621. ;;; call. There are 2 reasons for that:
  1622. ;;;   - the protocol below is exposed to mimic completely the one written in C
  1623. ;;;   - the currified protocol would be imho inefficient in C.
  1624. ;;;
  1625.  
  1626. (define-method (apply-generic (gf <generic>) args)
  1627.   (if (null? (slot-ref gf 'methods))
  1628.       (no-method gf args))
  1629.   (let ((methods (compute-applicable-methods gf args)))
  1630.     (if methods
  1631.     (apply-methods gf (sort-applicable-methods gf methods args) args)
  1632.     (no-applicable-method gf args))))
  1633.  
  1634. ;; compute-applicable-methods is bound to %compute-applicable-methods.
  1635. ;; *fixme* use let
  1636. (define %%compute-applicable-methods
  1637.   (make <generic> #:name 'compute-applicable-methods))
  1638.  
  1639. (define-method (%%compute-applicable-methods (gf <generic>) args)
  1640.   (%compute-applicable-methods gf args))
  1641.  
  1642. (set! compute-applicable-methods %%compute-applicable-methods)
  1643.  
  1644. (define-method (sort-applicable-methods (gf <generic>) methods args)
  1645.   (let ((targs (map class-of args)))
  1646.     (sort methods (lambda (m1 m2) (method-more-specific? m1 m2 targs)))))
  1647.  
  1648. (define-method (method-more-specific? (m1 <method>) (m2 <method>) targs)
  1649.   (%method-more-specific? m1 m2 targs))
  1650.  
  1651. (define-method (apply-method (gf <generic>) methods build-next args)
  1652.   (apply (method-procedure (car methods))
  1653.      (build-next (cdr methods) args)
  1654.      args))
  1655.  
  1656. (define-method (apply-methods (gf <generic>) (l <list>) args)
  1657.   (letrec ((next (lambda (procs args)
  1658.            (lambda new-args
  1659.              (let ((a (if (null? new-args) args new-args)))
  1660.                (if (null? procs)
  1661.                (no-next-method gf a)
  1662.                (apply-method gf procs next a)))))))
  1663.     (apply-method gf l next args)))
  1664.  
  1665. ;; We don't want the following procedure to turn up in backtraces:
  1666. (for-each (lambda (proc)
  1667.         (set-procedure-property! proc 'system-procedure #t))
  1668.       (list slot-unbound
  1669.         slot-missing
  1670.         no-next-method
  1671.         no-applicable-method
  1672.         no-method
  1673.         ))
  1674.  
  1675. ;;;
  1676. ;;; {<composite-metaclass> and <active-metaclass>}
  1677. ;;;
  1678.  
  1679. ;(autoload "active-slot"    <active-metaclass>)
  1680. ;(autoload "composite-slot" <composite-metaclass>)
  1681. ;(export <composite-metaclass> <active-metaclass>)
  1682.  
  1683. ;;;
  1684. ;;; {Tools}
  1685. ;;;
  1686.  
  1687. ;; list2set
  1688. ;;
  1689. ;; duplicate the standard list->set function but using eq instead of
  1690. ;; eqv which really sucks a lot, uselessly here
  1691. ;;
  1692. (define (list2set l)           
  1693.   (let loop ((l l)
  1694.          (res '()))
  1695.     (cond               
  1696.      ((null? l) res)
  1697.      ((memq (car l) res) (loop (cdr l) res))
  1698.      (else (loop (cdr l) (cons (car l) res))))))
  1699.  
  1700. (define (class-subclasses c)
  1701.   (letrec ((allsubs (lambda (c)
  1702.               (cons c (mapappend allsubs
  1703.                      (class-direct-subclasses c))))))
  1704.     (list2set (cdr (allsubs c)))))
  1705.  
  1706. (define (class-methods c)
  1707.   (list2set (mapappend class-direct-methods
  1708.                (cons c (class-subclasses c)))))
  1709.  
  1710. ;;;
  1711. ;;; {Final initialization}
  1712. ;;;
  1713.  
  1714. ;; Tell C code that the main bulk of Goops has been loaded
  1715. (%goops-loaded)
  1716.